﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ITAP.Core.Modelling.Primitives;
using ITAP.Core.Modelling;

namespace ITAP.Core.Calculations
{
    public class IntersectionCache
    {
        public static bool Enabled = false;
        private static LinkedList<PrimitivePair> stack = new LinkedList<PrimitivePair>();
        public static int MaximumHashSize = 5000;
        //        public static int MinimumHashSize = 4000;

        private static Dictionary<PrimitivePair, ModelPoint[]> hash = new Dictionary<PrimitivePair, ModelPoint[]>();

        public static ModelPoint[] Get(PrimitivePair key)
        {
            if (!Enabled)
                return null;

            ModelPoint[] intersections = null;
            ModelPoint[] result = null;
            hash.TryGetValue(key, out intersections);
            if (intersections != null)
            {
                int counter = 0;
                result = new ModelPoint[intersections.Length];
                foreach (ModelPoint point in intersections)
                {
                    result[counter] = point.Clone() as ModelPoint;
                    counter++;
                }
                stack.Remove(key);
                stack.AddLast(key);
            }
            IntersectionCache.ClearHash();
            return result;
        }

        public static void Add(PrimitivePair key, ModelPoint[] value)
        {
            if (!Enabled)
                return;

            PrimitivePair keyClone = key.Clone() as PrimitivePair;
            ModelPoint[] valueClones = new ModelPoint[value.Length];
            int counter = 0;
            foreach (ModelPoint point in value)
            {
                valueClones[counter] = point.Clone() as ModelPoint;
                counter++;
            }

            lock (hash)
            {
                if (hash.ContainsKey(keyClone))
                    return;
                else
                {
                    stack.AddLast(keyClone);
                    hash.Add(keyClone, valueClones);
                }
            }
            IntersectionCache.ClearHash();
        }

        private static void ClearHash()
        {
            if (!Enabled)
                return;

            if (stack.Count > MaximumHashSize)
            {
                foreach (PrimitivePair _key in stack)
                {
                    hash.Remove(_key);
                }
                stack.Clear();
            }
        }
    }

    public class PrimitivePair : ICloneable
    {
        private IEndedPrimitive primitive1;

        public IEndedPrimitive Primitive1
        {
            get { return primitive1; }
            set { primitive1 = value; }
        }
        private IEndedPrimitive primitive2;

        public IEndedPrimitive Primitive2
        {
            get { return primitive2; }
            set { primitive2 = value; }
        }

        public PrimitivePair(IEndedPrimitive primitive1, IEndedPrimitive primitive2)
        {
            this.primitive1 = primitive1;
            this.primitive2 = primitive2;
        }

        public override int GetHashCode()
        {
            return primitive1.GetHashCode() ^ primitive2.GetHashCode();
        }

        #region ICloneable Members

        public object Clone()
        {
            PrimitivePair clone = new PrimitivePair(this.primitive1.Clone() as IEndedPrimitive, this.primitive2.Clone() as IEndedPrimitive);
            return clone;
        }

        public override bool Equals(object obj)
        {
            if (!(obj is PrimitivePair))
                return false;

            PrimitivePair pair = obj as PrimitivePair;
            if (pair.primitive1.Equals(this.primitive1) && pair.primitive2.Equals(this.primitive2))
                return true;
            else
                return false;
        }

        #endregion
    }
}
